/**
 * 
 */
package org.hackystat.ui.sensordatabrowser.client;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.WindowResizeListener;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * @author David J. Nickles
 *
 */
public class DataPanels implements WindowResizeListener {

  private VerticalPanel dataPanel;
  private Image dataPanelImage;
  private HTML dataPanelFeedback;
  private EventTree dataTree;
  private Session session;
  private ScrollPanel scrollPanel;
  private Date dateChosen;
  private int lastCallTotal;
  private static final int HOFFSET = 342;
  private static final int VOFFSET = 170;
  
  /**
   * Constructs a new Data panel.
   * @param session parameters.
   */
  public DataPanels(Session session) {
    this.session = session;
    this.dataPanel = new VerticalPanel();
    this.dataPanel.setStyleName(Styles.DATAPANELSTYLE);
    HorizontalPanel dataColumns = new HorizontalPanel();
    dataColumns.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
    dataColumns.addStyleName("dataPanelHeader");
    dataColumns.setWidth("100%");
    this.dataPanelImage = new Image(Images.OPEN_BOOK);
    this.dataPanelImage.setStyleName(Styles.STATUSIMAGESTYLE);
    dataColumns.add(this.dataPanelImage);
    VerticalPanel dataCol2Rows = new VerticalPanel();
    Label dataPanelTitle = new Label("Data Browser");
    dataCol2Rows.add(dataPanelTitle);
    dataPanelTitle.setStyleName(Styles.SMALLLABELSTYLE);
    this.dataPanelFeedback = new HTML("Displays the selected day's data log.");
    this.dataPanelFeedback.setStyleName(Styles.EXAMPLELABELSTYLE);
    dataCol2Rows.add(this.dataPanelFeedback);
    dataColumns.add(dataCol2Rows);
    this.dataPanel.add(dataColumns);
    
    this.dataTree = new EventTree(session);
    this.scrollPanel = new ScrollPanel(this.dataTree);
    this.dataPanel.add(this.scrollPanel);

    RootPanel.get("data").clear();
    RootPanel.get("data").add(this.dataPanel);
    
    Window.addWindowResizeListener(this);
    onWindowResized(Window.getClientWidth(), Window.getClientHeight()); //NOPMD
  }

  /**
   * The date to aggregate data for.
   * @param date specified.
   */
  public void update(Date date) {
    this.dateChosen = date;
    rpcGetDaySummary();
  }
  
  /**
   * This method digests the response from the RPC call into local data structures.
   * @param dataCollection an ArrayList of ArrayLists of Strings containing the sensor data.
   * 
   * @gwt.typeArgs dataCollection <java.util.ArrayList<java.lang.String>>
   */ 
  public void work(ArrayList dataCollection) {
    this.dataPanelImage.setUrl(Images.CAL_IMAGE);
    this.dataPanelFeedback.setHTML("Browsing sensor data for " 
      + DateTimeFactories.getInstance().getDayfactory().format(
        this.dateChosen) + Styles.NEWLINECHAR + "Select a day to view.");
    this.dataPanelImage.setUrl(Images.WAIT_IMAGE);
    this.dataPanelFeedback.setText("Processing and displaying data for " 
      + DateTimeFactories.getInstance().getDayfactory().format(this.dateChosen));
    this.scrollPanel.setWidget(this.dataTree.resetTree(dataCollection));
    this.lastCallTotal = this.dataTree.getDataCount();
    String actiontimestamp = 
      DateTimeFactories.getInstance().getDayfactory().format(this.dateChosen);
    if (this.lastCallTotal == 0) {
      this.dataPanelFeedback.setHTML("No sensor data recorded on " + actiontimestamp);
    } 
    else {
      if (this.lastCallTotal == 1) {
        this.dataPanelFeedback.setHTML("1 sensor data instance recorded on " + actiontimestamp);
      } 
      else {
        this.dataPanelFeedback.setHTML(this.lastCallTotal + " sensor data instances recorded on "
          + actiontimestamp);  
      }
    }
    this.dataPanelImage.setUrl(Images.OPEN_BOOK);
  }
  
  /**
   * This method performs an asynchronous remote call out to the servlet service
   * for particular sensor data over a specified period as indicated in the URI.
   * Requires this.dayChosen to be previously set.
   */ 
  public void rpcGetDaySummary() {
    this.dataPanelImage.setUrl(Images.WAIT_IMAGE);
    this.dataPanelFeedback.setText("Requesting sensor data for " 
      + DateTimeFactories.getInstance().getDayfactory().format(this.dateChosen) 
      + " from the SensorBase.");
    if (session.getUser() != null) {
      RPCServiceFactory.getInstance().getService().getDaySummary(session.getSensorbaseHost(),
        Session.DEFAULT, session.getUser(), session.getPassword(), 
        DateTimeFactories.toQuantizedXMLFormat(this.dateChosen), 
        new AsyncCallback()
        {
          public void onSuccess(Object result) {
            /** @gwt.typeArgs result <java.util.ArrayList<java.lang.String>> */
            work((ArrayList) result);
          }

          public void onFailure(Throwable caught) {
            if (caught instanceof com.google.gwt.user.client.rpc.InvocationException) {
              Window.alert(RPCServiceFactory.PRCERRORNAME + "Cannot invoke method on servlet.");
            } 
            else {
              Window.alert(RPCServiceFactory.PRCERRORNAME + caught.toString());
            }
          }
        });
    }
  }

  /** 
   * Listens for user resizing of the window.
   * @param width of the adjusted window..
   * @param height of the adjusted window.
   */
  public void onWindowResized(int width, int height) {
    int adjHeight = height;
    if (height < 460) {
      adjHeight = 460;
    }
    this.dataPanel.setWidth(Integer.toString(width - HOFFSET) + Styles.PIXELSUFFIX);
    this.dataPanel.setHeight(Integer.toString(adjHeight - VOFFSET) + Styles.PIXELSUFFIX);
    this.scrollPanel.setWidth(Integer.toString(width - HOFFSET) + Styles.PIXELSUFFIX);
    this.scrollPanel.setHeight(Integer.toString(adjHeight - VOFFSET) + Styles.PIXELSUFFIX);
  }
}
